﻿/* ----------------------------------------------------------------------------
 * Copyright (c) Philip Stears 
 *
 * This source code is subject to terms and conditions of the Microsoft Public 
 * License (Ms-PL).
 * 
 * By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * To request a copy of the Microsoft Public License, send a request by email
 * to license@connectbasic.net.
 *
 * This notice must not be removed from this software.
 * ---------------------------------------------------------------------------- */

namespace ConnectBasic.ObjectModel
{
    using System.Collections.Generic;
    using ConnectBasic.Execution;
    using DlrExpression = Microsoft.Linq.Expressions.Expression;

    /// <summary>
    /// Represents a do...until statement.
    /// </summary>
    public class DoUntilStatement : StatementNodeBase
    {
        private ExpressionBase mCondition;
        private Block mStatements;


        /// <summary>
        /// Initializes a new instance of the <see cref="DoUntilStatement" /> class.
        /// </summary>
        /// <param name="condition">The condition which gets evaluated with each iteration of the loop.</param>
        /// <param name="statements">The statements which get executed with each iteration of the loop.</param>
        public DoUntilStatement(ExpressionBase condition, IEnumerable<StatementNodeBase> statements)
            : this(condition, new Block(statements))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DoUntilStatement" /> class.
        /// </summary>
        /// <param name="condition">The condition which gets evaluated with each iteration of the loop.</param>
        /// <param name="statements">The statements which get executed with each iteration of the loop.</param>
        public DoUntilStatement(ExpressionBase condition, Block statements)
        {
            mCondition = condition;
            mStatements = statements;
        }

        /// <summary>
        /// Gets the condition which gets evaluated with each iteration of the loop.
        /// </summary>
        public ExpressionBase Condition
        {
            get { return mCondition; }
        }

        /// <summary>
        /// Gets the statements which get executed with each iteration of the loop.
        /// </summary>
        public Block Statements
        {
            get { return mStatements; }
        }

        /// <inheritdoc />
        public override DlrExpression Compile(BasicCodeGenerator gen)
        {            
            var condition = GeneratorUtil.Convert(mCondition.Compile(gen), typeof(bool));

            // Make sure we're setup in case one of the statements is an Exit Do
            var exitLabel = DlrExpression.Label();

            gen.PushFlowContext(BasicTokenKind.KeywordDo, exitLabel);
            var loopStatements = mStatements.Compile(gen);
            gen.PopFlowContext();

            // The condition; wanted by the helper; determines whether the loop continues
            return Microsoft.Scripting.Ast.Utils.Loop(
                    DlrExpression.Not(condition),
                    null,
                    loopStatements,
                    null,
                    exitLabel, 
                    null).Reduce();
        }
    }
}
